home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / SATAN11.ZIP / SRC / PORT_SCA / UDP_SCAN.C < prev   
Encoding:
C/C++ Source or Header  |  1995-04-04  |  15.5 KB  |  616 lines

  1.  /*
  2.   * udp-scan - determine available udp services
  3.   * 
  4.   * Author: Wietse Venema.
  5.   */
  6.  
  7. #include <sys/types.h>
  8. #include <sys/param.h>
  9. #include <sys/socket.h>
  10. #include <sys/time.h>
  11.  
  12. #include <netinet/in_systm.h>
  13. #include <netinet/in.h>
  14. #include <netinet/ip.h>
  15. #include <netinet/ip_icmp.h>
  16. #include <netinet/udp.h>
  17.  
  18. #include <errno.h>
  19. #include <netdb.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. extern int errno;
  24.  
  25. #ifndef __STDC__
  26. extern char *strerror();
  27. #endif
  28.  
  29. extern char *optarg;
  30. extern int optind;
  31.  
  32. #define offsetof(t,m)    (size_t)(&(((t *)0)->m))
  33.  
  34. #ifndef FD_SET
  35. #include <sys/select.h>
  36. #endif
  37.  
  38. #include "lib.h"
  39.  
  40. #define LOAD_LIMIT    100        /* default max nr of open sockets */
  41. #define AVG_MARGIN    10        /* safety margin */
  42.  
  43.  /*
  44.   * In order to protect ourselves against dead hosts, we first probe UDP port
  45.   * 1. If we do not get an ICMP error (no listener or host unreachable) we
  46.   * assume this host is dead. If we do get an ICMP error, we have an estimate
  47.   * of the roundtrip time. The test port can be changed with the -p option.
  48.   */
  49. char   *test_port = "1";
  50. int     test_portno;
  51.  
  52. #define YES     1
  53. #define NO      0
  54.  
  55. int     verbose = 0;            /* default silent mode */
  56. int     open_file_limit;        /* max nr of open files */
  57.  
  58.  /*
  59.   * We attempt to send as many probes per roundtrip time as network capacity
  60.   * permits. With UDP we must do our own retransmission and congestion
  61.   * handling.
  62.   */
  63. int     hard_limit = LOAD_LIMIT;    /* max nr of open sockets */
  64. int     soft_limit;            /* slowly-moving load limit */
  65.  
  66. struct timeval now;            /* global time after select() */
  67. int     ports_busy;            /* number of open sockets */
  68. int     want_err = 0;            /* show reachable/unreachable */
  69. int     show_all = 0;            /* show all ports */
  70.  
  71.  /*
  72.   * Information about ongoing probes is sorted by time of last transmission.
  73.   */
  74. struct port_info {
  75.     RING    ring;            /* round-robin linkage */
  76.     struct timeval last_probe;        /* time of last probe */
  77.     int     port;            /* port number */
  78.     int     pkts;            /* number of packets sent */
  79. };
  80.  
  81. struct port_info *port_info = 0;
  82. RING    active_ports;            /* active sockets list head */
  83. RING    dead_ports;            /* dead sockets list head */
  84. struct port_info *find_port_info();    /* retrieve port info */
  85.  
  86.  /*
  87.   * Performance statistics. These are used to update the transmission window
  88.   * size depending on transmission error rates.
  89.   */
  90. double  avg_irt = 0;            /* inter-reply arrival time */
  91. double  avg_rtt = 0;            /* round-trip time */
  92. double  avg_pkts = 1;            /* number of packets sent per reply */
  93. int     probes_sent = 0;        /* probes sent */
  94. int     probes_done = 0;        /* finished probes */
  95. int     replies;            /* number of good single probes */
  96. struct timeval last_reply;        /* time of last reply */
  97.  
  98. int     send_sock;            /* send probes here */
  99. int     icmp_sock;            /* read replies here */
  100. fd_set  icmp_sock_mask;            /* select() read mask */
  101. static struct sockaddr_in sin;
  102.  
  103.  /*
  104.   * Helpers...
  105.   */
  106.  
  107. #define time_since(t) (now.tv_sec - t.tv_sec + 1e-6 * (now.tv_usec - t.tv_usec))
  108. #define sock_age(sp) time_since(sp->last_probe)
  109. double  average();
  110. struct port_info *add_port();
  111.  
  112. /* main - command-line interface */
  113.  
  114. main(argc, argv)
  115. int     argc;
  116. char   *argv[];
  117. {
  118.     int     c;
  119.     struct protoent *pe;
  120.     char  **ports;
  121.  
  122.     progname = argv[0];
  123.     if (geteuid())
  124.     error("This program needs root privileges");
  125.  
  126.     open_file_limit = open_limit();
  127.  
  128.     while ((c = getopt(argc, argv, "al:p:uUv")) != EOF) {
  129.     switch (c) {
  130.     case 'a':
  131.         show_all = 1;
  132.         break;
  133.     case 'l':
  134.         if ((hard_limit = atoi(optarg)) <= 0)
  135.         usage("invalid load limit");
  136.         break;
  137.     case 'p':
  138.         test_port = optarg;
  139.         break;
  140.     case 'u':
  141.         want_err = EHOSTUNREACH;
  142.         break;
  143.     case 'U':
  144.         want_err = ~EHOSTUNREACH;
  145.         break;
  146.     case 'v':
  147.         verbose = 1;
  148.         break;
  149.     default:
  150.         usage((char *) 0);
  151.         break;
  152.     }
  153.     }
  154.     argc -= (optind - 1);
  155.     argv += (optind - 1);
  156.     if (argc < 3)
  157.     usage("missing argument");
  158.  
  159.     if (hard_limit > open_file_limit - 10)
  160.     hard_limit = open_file_limit - 10;
  161.     soft_limit = hard_limit + 1;
  162.     init_port_info();
  163.  
  164.     if ((pe = getprotobyname("icmp")) == 0)
  165.     error("icmp: unknown protocol");
  166.     if ((icmp_sock = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
  167.     error("icmp socket: %m");
  168.     FD_ZERO(&icmp_sock_mask);
  169.     FD_SET(icmp_sock, &icmp_sock_mask);
  170.  
  171.     if ((send_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  172.     error("socket: %m");
  173.  
  174.     /*
  175.      * First do a test probe to see if the host is up, and to establish the
  176.      * round-trip time. This requires that the test port is not used.
  177.      */
  178.     memset((char *) &sin, 0, sizeof(sin));
  179.     sin.sin_addr = find_addr(argv[1]);
  180.     sin.sin_family = AF_INET;
  181.  
  182.     gettimeofday(&now, (struct timezone *) 0);
  183.     last_reply = now;
  184.  
  185.     /*
  186.      * Calibrate round-trip time and dead time.
  187.      */
  188.     for (;;) {
  189.     scan_ports(test_port);
  190.     while (ports_busy > 0)
  191.         monitor_ports();
  192.     if (avg_rtt)
  193.         break;
  194.     sleep(1);
  195.     }
  196.     scan_ports(test_port);
  197.  
  198.     /*
  199.      * Scan those ports.
  200.      */
  201.     for (ports = argv + 2; *ports; ports++)
  202.     scan_ports(*ports);
  203.  
  204.     /*
  205.      * All ports probed, wait for replies to trickle back.
  206.      */
  207.     while (ports_busy > 0)
  208.     monitor_ports();
  209.  
  210.     return (0);
  211. }
  212.  
  213. /* usage - explain command syntax */
  214.  
  215. usage(why)
  216. char   *why;
  217. {
  218.     if (why)
  219.     remark(why);
  220.     error("usage: %s [-apuU] [-l load] host ports...", progname);
  221. }
  222.  
  223. /* scan_ports - scan ranges of ports */
  224.  
  225. scan_ports(service)
  226. char   *service;
  227. {
  228.     char   *cp;
  229.     int     min_port;
  230.     int     max_port;
  231.     int     port;
  232.     struct port_info *sp;
  233.  
  234.     if (service == test_port)
  235.     test_portno = atoi(test_port);
  236.  
  237.     /*
  238.      * Translate service argument to range of port numbers.
  239.      */
  240.     if ((cp = strchr(service, '-')) != 0) {
  241.     *cp++ = 0;
  242.     min_port = (service[0] ? ntohs(find_port(service, "udp")) : 1);
  243.     max_port = (cp[0] ? ntohs(find_port(cp, "udp")) : 65535);
  244.     } else {
  245.     min_port = max_port = ntohs(find_port(service, "udp"));
  246.     }
  247.  
  248.     /*
  249.      * Iterate over each port in the given range. Adjust the number of
  250.      * simultaneous probes to the capacity of the network.
  251.      */
  252.     for (port = min_port; port <= max_port; port++) {
  253.     sp = add_port(port);
  254.     write_port(sp);
  255.     monitor_ports();
  256.     }
  257. }
  258.  
  259. /* monitor_ports - watch for socket activity */
  260.  
  261. monitor_ports()
  262. {
  263.     do {
  264.     struct port_info *sp;
  265.  
  266.     /*
  267.      * When things become quiet, examine the port that we haven't looked
  268.      * at for the longest period of time.
  269.      */
  270.     receive_answers();
  271.  
  272.     if (ports_busy == 0)
  273.         return;
  274.  
  275.     sp = (struct port_info *) ring_succ(&active_ports);
  276.     if (sp->pkts > avg_pkts * AVG_MARGIN) {
  277.         report_and_drop_port(sp, 0);
  278.     } else
  279.  
  280.         /*
  281.          * Strategy depends on whether transit times dominate (probe
  282.          * multiple ports in parallel, retransmit when no reply was
  283.          * received for at least one round-trip period) or by dead time
  284.          * (probe one port at a time, retransmit when no reply was
  285.          * received for some fraction of the inter-reply period).
  286.          */
  287.         if (sock_age(sp) > (avg_rtt == 0 ? 1 :
  288.                 2 * avg_rtt < avg_irt ? avg_irt / 4 :
  289.                 1.5 * avg_rtt)) {
  290.         write_port(sp);
  291.     }
  292.  
  293.     /*
  294.      * When all ports being probed seem to be active, send a test probe
  295.      * to see if the host is still alive.
  296.      */
  297.     if (time_since(last_reply) > 3 * (avg_rtt == 0 ? 1 :
  298.                       avg_rtt < avg_irt ? avg_irt : avg_rtt)
  299.         && find_port_info(test_portno) == 0) {
  300.         last_reply = now;
  301.         write_port(add_port(test_portno));
  302.     }
  303.     } while (ports_busy && (ports_busy >= hard_limit
  304.                 || ports_busy >= probes_done
  305.                 || ports_busy >= soft_limit));
  306. }
  307.  
  308. /* receive_answers - receive reactions to probes */
  309.  
  310. receive_answers()
  311. {
  312.     fd_set  read_mask;
  313.     struct timeval waitsome;
  314.     double  delay;
  315.     int     answers;
  316.  
  317.     /*
  318.      * The timeout is less than the inter-reply arrival time or we would not
  319.      * be able to increase the load.
  320.      */
  321.     delay = (2 * avg_rtt < avg_irt ? avg_irt / 3 : avg_rtt / (1 + ports_busy * 4));
  322.     waitsome.tv_sec = delay;
  323.     waitsome.tv_usec = (delay - waitsome.tv_sec) * 1000000;
  324.  
  325.     read_mask = icmp_sock_mask;
  326.     if ((answers = select(icmp_sock + 1, &read_mask, (fd_set *) 0, (fd_set *) 0,
  327.               &waitsome)) < 0)
  328.     error("select: %m");
  329.  
  330.     gettimeofday(&now, (struct timezone *) 0);
  331.  
  332.     /*
  333.      * For each answer that we receive without retransmissions, update the
  334.      * average roundtrip time.
  335.      */
  336.     if (answers > 0) {
  337.     if (FD_ISSET(icmp_sock, &read_mask))
  338.         receive_icmp(icmp_sock);
  339.     }
  340.     return (answers);
  341. }
  342.  
  343. /* receive_icmp - receive and decode ICMP message */
  344.  
  345. receive_icmp(sock)
  346. int     sock;
  347. {
  348.     union {
  349.     char    chars[BUFSIZ];
  350.     struct ip ip;
  351.     }       buf;
  352.     int     data_len;
  353.     int     hdr_len;
  354.     struct ip *ip;
  355.     struct icmp *icmp;
  356.     struct udphdr *udp;
  357.     struct port_info *sp;
  358.  
  359.     if ((data_len = recv(sock, (char *) &buf, sizeof(buf), 0)) < 0) {
  360.     error("error: recv: %m");
  361.     return;
  362.     }
  363.  
  364.     /*
  365.      * Extract the IP header.
  366.      */
  367.     ip = &buf.ip;
  368.     if (ip->ip_p != IPPROTO_ICMP) {
  369.     error("error: not ICMP proto (%d)", ip->ip_p);
  370.     return;
  371.     }
  372.  
  373.     /*
  374.      * Extract the IP payload.
  375.      */
  376.     hdr_len = ip->ip_hl << 2;
  377.     if (data_len - hdr_len < ICMP_MINLEN) {
  378.     remark("short ICMP packet (%d bytes)", data_len);
  379.     return;
  380.     }
  381.     icmp = (struct icmp *) ((char *) ip + hdr_len);
  382.     data_len -= hdr_len;
  383.  
  384.     if (icmp->icmp_type != ICMP_UNREACH)
  385.     return;
  386.  
  387.     /*
  388.      * Extract the offending IP header.
  389.      */
  390.     if (data_len < offsetof(struct icmp, icmp_ip) + sizeof(icmp->icmp_ip)) {
  391.     remark("short IP header in ICMP");
  392.     return;
  393.     }
  394.     ip = &(icmp->icmp_ip);
  395.     if (ip->ip_p != IPPROTO_UDP)
  396.     return;
  397.     if (ip->ip_dst.s_addr != sin.sin_addr.s_addr)
  398.     return;
  399.  
  400.     /*
  401.      * Extract the offending UDP header.
  402.      */
  403.     hdr_len = ip->ip_hl << 2;
  404.     udp = (struct udphdr *) ((char *) ip + hdr_len);
  405.     data_len -= hdr_len;
  406.     if (data_len < sizeof(struct udphdr)) {
  407.     remark("short UDP header in ICMP");
  408.     return;
  409.     }
  410.  
  411.     /*
  412.      * Process ICMP subcodes.
  413.      */
  414.     switch (icmp->icmp_code) {
  415.     case ICMP_UNREACH_NET:
  416.     error("error: network unreachable");
  417.     /* NOTREACHED */
  418.     case ICMP_UNREACH_HOST:
  419.     if (sp = find_port_info(ntohs(udp->uh_dport)))
  420.         process_reply(sp, EHOSTUNREACH);
  421.     break;
  422.     case ICMP_UNREACH_PROTOCOL:
  423.     error("error: protocol unreachable");
  424.     /* NOTREACHED */
  425.     case ICMP_UNREACH_PORT:
  426.     if (sp = find_port_info(ntohs(udp->uh_dport)))
  427.         process_reply(sp, ECONNREFUSED);
  428.     break;
  429.     }
  430. }
  431.  
  432. /* process_reply - process reply */
  433.  
  434. process_reply(sp, err)
  435. struct port_info *sp;
  436. int     err;
  437. {
  438.     double  age = sock_age(sp);
  439.     int     pkts = sp->pkts;
  440.     double  irt = time_since(last_reply);
  441.  
  442.     /*
  443.      * Don't believe everything.
  444.      */
  445.     if (age > 5) {
  446.     age = 5;
  447.     } else if (age < 0) {
  448.     age = 1;
  449.     }
  450.     if (irt > 5) {
  451.     irt = 5;
  452.     } else if (irt < 0) {
  453.     irt = 1;
  454.     }
  455.  
  456.     /*
  457.      * We jump some hoops for calibration purposes. First we estimate the
  458.      * round-trip time: we use this to decide when to retransmit when network
  459.      * transit time dominates.
  460.      * 
  461.      * Next thing to do is to estimate the inter-reply time, in case the sender
  462.      * has a "dead time" for ICMP replies; I have seen this happen with some
  463.      * Cisco routers and with Solaris 2.4. The first reply will come fast;
  464.      * subsequent probes will be ignored for a period of up to one second.
  465.      * When this happens the retransmission period should be based on the
  466.      * inter-reply time and not on the average round-trip time.
  467.      */
  468.     last_reply = now;
  469.     replies++;
  470.     if (pkts == 1)
  471.     avg_rtt = (avg_rtt == 0 ? age :        /* adopt initial rtt */
  472.            average(age, avg_rtt));    /* normal processing */
  473.     avg_irt = (avg_irt == 0 ? 1 :        /* prepare for irt
  474.                          * calibration */
  475.            avg_irt == 1 ? irt :        /* adopt initial irt */
  476.            average(irt, avg_irt));        /* normal processing */
  477.     avg_pkts = average((double) pkts, avg_pkts);
  478.     if (verbose)
  479.     printf("%d:age %.3f irt %.3f pkt %d ports %2d soft %2d done %2d avrtt %.3f avpkt %.3f avirt %.3f\n",
  480.            sp->port, age, irt, pkts,
  481.            ports_busy, soft_limit,
  482.            probes_done, avg_rtt, avg_pkts, avg_irt);
  483.     report_and_drop_port(sp, err);
  484. }
  485.  
  486. /* report_and_drop_port - report what we know about this service */
  487.  
  488. report_and_drop_port(sp, err)
  489. struct port_info *sp;
  490. int     err;
  491. {
  492.     struct servent *se;
  493.  
  494.     if (probes_done == 0) {
  495.     if (err == 0)
  496.         error("are we talking to a dead host or network?");
  497.     } else if (show_all || want_err == err || (want_err < 0 && want_err != ~err)) {
  498.     printf("%d:%s:", sp->port,
  499.            (se = getservbyport(htons(sp->port), "udp")) ?
  500.            se->s_name : "UNKNOWN");
  501.     if (err && show_all)
  502.         printf("%s", strerror(err));
  503.     printf("\n");
  504.     fflush(stdout);
  505.     }
  506.     drop_port(sp);
  507. }
  508.  
  509. /* average - quick-rise, slow-decay moving average */
  510.  
  511. double  average(new, old)
  512. double  new;
  513. double  old;
  514. {
  515.     if (new > old) {                /* quick rise */
  516.     return ((new + old) / 2);
  517.     } else {                    /* slow decay */
  518.     return (0.1 * new + 0.9 * old);
  519.     }
  520. }
  521.  
  522. /* add_port - say this port is being probed */
  523.  
  524. struct port_info *add_port(port)
  525. int     port;
  526. {
  527.     struct port_info *sp = (struct port_info *) ring_succ(&dead_ports);
  528.  
  529.     ring_detach((RING *) sp);
  530.     sp->port = port;
  531.     sp->pkts = 0;
  532.     ports_busy++;
  533.     ring_append(&active_ports, (RING *) sp);
  534.     return (sp);
  535. }
  536.  
  537. /* write_port - write to port, update statistics */
  538.  
  539. write_port(sp)
  540. struct port_info *sp;
  541. {
  542.     char    ch = 0;
  543.  
  544.     ring_detach((RING *) sp);
  545.     sin.sin_port = htons(sp->port);
  546.     sp->last_probe = now;
  547.     sendto(send_sock, &ch, 1, 0, (struct sockaddr *) & sin, sizeof(sin));
  548.     probes_sent++;
  549.     sp->pkts++;
  550.     ring_prepend(&active_ports, (RING *) sp);
  551.  
  552.     /*
  553.      * Reduce the sending window when the first retransmission happens. Back
  554.      * off when retransmissions dominate. Occasional retransmissons will keep
  555.      * the load unchanged.
  556.      */
  557.     if (sp->pkts > 1) {
  558.     replies--;
  559.     if (soft_limit > hard_limit) {
  560.         soft_limit = (ports_busy + 1) / 2;
  561.     } else if (replies < 0 && avg_irt) {
  562.         soft_limit = 0.5 + 0.5 * (soft_limit + avg_rtt / avg_irt);
  563.         replies = soft_limit / 2;
  564.     }
  565.     }
  566. }
  567.  
  568. /* drop_port - release port info, update statistics */
  569.  
  570. drop_port(sp)
  571. struct port_info *sp;
  572. {
  573.     ports_busy--;
  574.     probes_done++;
  575.     ring_detach((RING *) sp);
  576.     ring_append(&dead_ports, (RING *) sp);
  577.  
  578.     /*
  579.      * Increase the load when a sufficient number of probes succeeded.
  580.      * Occasional retransmissons will keep the load unchanged.
  581.      */
  582.     if (replies > soft_limit) {
  583.     replies = soft_limit / 2;
  584.     if (soft_limit < hard_limit)
  585.         soft_limit++;
  586.     }
  587. }
  588.  
  589. /* init_port_info - initialize port info pool */
  590.  
  591. init_port_info()
  592. {
  593.     struct port_info *sp;
  594.  
  595.     port_info = (struct port_info *) mymalloc(hard_limit * sizeof(*port_info));
  596.     ring_init(&active_ports);
  597.     ring_init(&dead_ports);
  598.     for (sp = port_info; sp < port_info + hard_limit; sp++)
  599.     ring_append(&dead_ports, (RING *) sp);
  600. }
  601.  
  602. /* find_port_info - lookup port info */
  603.  
  604. struct port_info *find_port_info(port)
  605. int     port;
  606. {
  607.     struct port_info *sp;
  608.  
  609.     for (sp = (struct port_info *) ring_succ(&active_ports);
  610.      sp != (struct port_info *) & active_ports;
  611.      sp = (struct port_info *) ring_succ((RING *) sp))
  612.     if (sp->port == port)
  613.         return (sp);
  614.     return (0);
  615. }
  616.